import collections
import os


# 存储用户信息的
class User:
    def __init__(self, username, password):
        self.username = username
        self.password = password

    def check(self, uesrname, password):
        if self.username == uesrname and self.password == password:
            return True
        return False

    def action(self, wfunc, rfunc):
        raise NotImplementedError("该用户没有实现行为")


class Teacher(User):
    def __init__(self, username, password):
        super().__init__(username, password)
        self.nStep = 0

    def action(self, wfunc, rfunc):
        # 输入科目成绩函数
        def inputgrades(subject: str):
            while True:
                s = input('输入{}成绩:\r\n'.format(subject)).strip()
                try:
                    g = float(s)
                    if g < 0 or g > 100:
                        print('成绩在[0,100]范围内,请重新输入')
                    else:
                        return g
                except:
                    if s == 'quit':
                        return None
                    print('请输入[0,100]的数字')

        while True:
            # 是否输入用户成绩
            if self.nStep == 0:
                s = input('是否输入用户成绩:(是/否):\n').strip()
                if s == '是':
                    self.nStep = 1
                elif s == '否':
                    self.nStep = 2
                elif s == "quit":
                    return
                else:
                    print('输入错误！')
            # 是输入用户成绩
            elif self.nStep == 1:
                userName = ""
                s = input('输入需要录入成绩的学生名:\n').strip()
                if s == "":
                    print('用户名输入不能为空,请重新输入')
                    continue
                elif s == "quit":
                    return
                else:
                    userName = s
                grades = {'语文': None, '数学': None, '英语': None}
                # 输入用户成绩
                for k in grades:
                    g = inputgrades(k)
                    if g is None:
                        return
                    else:
                        grades[k] = g

                wfunc(userName, grades)

            # 查询用户成绩
            elif self.nStep == 2:
                userName = ''
                s = input('是否继续查询学生成绩(是/否)?\n').strip()
                if s == '是':
                    while True:
                        s = input('输入查询成绩的学生名:\n').strip()
                        if s == "":
                            print('用户名输入不能为空,请重新输入')
                        elif s == "quit":
                            return
                        else:
                            userName = s
                            break
                    # 查询用户成绩，并打印
                    rfunc(userName)
                    break
                elif s == '否':
                    break
                else:
                    print('输入错误')
            else:
                return


class Student(User):
    def action(self, wfunc, rfunc):
        ok = rfunc(self.username)
        if not ok:
            while True:
                s = input('是否查询下一个\n').strip()
                if s == "是":
                    return True
                elif s == "否":
                    return False
                else:
                    print('输入错误！')
        else:
            return True


class UserInfoManager:
    # 类静态变量存储用户信息
    USER = [
        Teacher('T', '1'),
        Teacher('M', '1'),
        Student('A', "1"),
        Student('B', '1'),
        Student('C', '1'),
        Student('D', '1'),
    ]
    #存被锁定的用户名
    LOCKUSER = collections.defaultdict(int)

    def __init__(self, fileName: str):
        self.fileName = fileName
        # 默认键值为字典,防止其报错
        self.gradesInfo = collections.defaultdict(dict)
        # 加载所有成绩
        self.readGrades()

    def check(self, bteacher, username, password):
        if self.LOCKUSER[username] >= 3:
            print('密码错误3次,该用户{}被锁定'.format(username))
            return False
        bOk = False
        for user in self.USER:
            if isinstance(user, Teacher if bteacher else Student):
                bOk = user.check(username, password)
                if bOk:
                    break
        if not bOk:
            self.LOCKUSER[username] += 1
            if self.LOCKUSER[username] >= 3:
                print('密码错误3次,该用户{}被锁定'.format(username))
                return False
        return bOk

    # 写成绩至文件
    def writeGrades(self, userName: str, grades: dict):
        self.gradesInfo[userName]['语文'] = grades['语文']
        self.gradesInfo[userName]['数学'] = grades['数学']
        self.gradesInfo[userName]['英语'] = grades['英语']

        with open(self.fileName, mode='w') as f:
            for user, grades in self.gradesInfo.items():
                f.write('{},{},{},{}\n'.format(user, *grades.values()))

    def searchgrades(self, username: str):
        if username in self.gradesInfo:
            print(self.gradesInfo[username])
            return True
        else:
            return False

    # 加载所有成绩
    def readGrades(self):
        lines = []
        if os.path.exists(self.fileName):
            with open(self.fileName, mode='r') as f:
                lines = f.readlines()
        for l in lines:
            v = l.split(',')
            if len(v) == 4:
                self.gradesInfo[v[0]]['语文'] = float(v[1].strip())
                self.gradesInfo[v[0]]['数学'] = float(v[2].strip())
                self.gradesInfo[v[0]]['英语'] = float(v[3].strip())

    def getUser(self, username: str, bTeacher):
        for user in self.USER:
            if isinstance(user, Teacher if bTeacher else Student):
                if user.username == username:
                    return user

    def Run(self):
        bTeacher = None
        nStep = 0
        UserName = ""
        while True:
            # 选择什么用户来登录
            if nStep == 0:
                s = input('使用什么用户登录？(T/S)\n').strip()
                if s == 'T':
                    bTeacher = True
                    nStep = 1
                elif s == 'S':
                    bTeacher = False
                    nStep = 1
                elif s == 'quit':
                    break
                else:
                    print("输入错误！")
            # 用户密码验证
            elif nStep == 1:
                s = input('输入用户名及密码：(格式：用户名,密码)\n')
                if s == 'quit':
                    break
                info = s.split(',')
                if len(info) != 2:
                    print("输入有误,请重新输入")
                else:
                    # 校验用户名和密码
                    if self.check(bTeacher, info[0], info[1]):
                        print('用户{}登录成功'.format(info[0]))
                        UserName = info[0]
                        nStep = 2
                    else:
                        print('用户{}登录失败'.format(info[0]))
            # 根据用户类型行为
            elif nStep == 2:
                if not self.getUser(UserName, bTeacher).action(self.writeGrades, self.searchgrades):
                    nStep = 0
                    return


userManager = UserInfoManager('123.txt')
userManager.Run()

# 测试出来的错误情况：
# 1. 使用教师身份登录时，直接查询学生成绩时，查出成绩后，程序直接退出。逻辑错误
# 2. 使用学生身份登录时，输入用户名和密码后，直接无限循环输出学生成绩。逻辑错误
# 3. 输入用户名和密码尽量错开。
# 4. 使用教室身份登录时，输入学生成绩，输入第一个学生成绩后，应该进入到输入或者查询成绩的循环。或者给出退出输入成绩流程的选择
# 而不是继续输入。